home *** CD-ROM | disk | FTP | other *** search
- Anti Debugging Tricks
-
- By:
-
- Inbar Raz
-
- Release number 2
-
- Today's anti debugging tricks devide into two categories:
-
- 1. Preventive actions;
- 2. Self-modifying code.
-
- Most debugging tricks, as for today, are used within viruses, in order to
- avoid dis-assembly of the virus, as it will be exampled later in this file.
- Another big part of anti debugging tricks is found with software protection
- programs, what use them in order to make the cracking of the protection
- harder.
-
- 1. Preventive actions:
- ----------------------
-
- Preventive actions are, basically, actions that the program takes in order
- to make the user unable to dis-assemble the code or trace it while running.
-
- 1.1. Interrupt disable:
-
- Interrupt disable is probably the most common form of anti-debugging
- trick. It can be done in several ways:
-
- 1.1.1. Hardware masking of interrupt:
-
- In order to avoid tracing of a code, one usually disables the
- interrupt via the 8259 Interrupt Controller, addressed by read/write
- actions to port 21h. The 8259 Interrupt Controller controls the IRQ
- lines. This means that any IRQ between 0 and 7 may be disabled by
- this action. Bit 0 is IRQ0, bit 1 is IRQ1 etc. Since IRQ1 is the
- keyboard interrupt, you may disable the keyboard without the
- debugger being able to bypass it.
-
- Example:
-
- CS:0100 E421 IN AL,21
- CS:0102 0C02 OR AL,02
- CS:0104 E621 OUT 21,AL
-
- Just as a side notice, the keyboard may be also disabled by
- commanding the Programmable Perepheral Interface (PPI), port 61h.
-
- Example:
-
- CS:0100 E461 IN AL,61
- CS:0102 0C80 OR AL,80
- CS:0104 E661 OUT 61,AL
-
- 1.1.2. Software masking of interrupt:
-
- This is quite an easy form of anti-debugging trick. All you have
- to do is simply replace the vectors of interrupts debuggers use/any
- other interrupt you will not be using or expecting to happen. Do not
- forget to restore the original vectors when you are finished.
- It is adviseable to use manual change of vector, as shown below,
- rather than to change it using interrupt 21h service 25h, because
- any debugger that has gained control of interrupt 21h may replace
- your vector with the debugger's. The example shows an interception
- of interrupt 03h - the breakpoint interrupt.
-
- Example:
-
- CS:0100 EB04 JMP 0106
- CS:0102 0000 ADD [BX+SI],AL
- CS:0104 0000 ADD [BX+SI],AL
- CS:0106 31C0 XOR AX,AX
- CS:0108 8EC0 MOV ES,AX
- CS:010A 268B1E0C00 MOV BX,ES:[000C]
- CS:010F 891E0201 MOV [0102],BX
- CS:0113 268B1E0E00 MOV BX,ES:[000E]
- CS:0118 891E0401 MOV [0104],BX
- CS:011C 26C7064C000000 MOV Word Ptr ES:[000C],0000
- CS:0123 26C7064E000000 MOV Word Ptr ES:[000E],0000
-
- 1.1.3. Vector manipulation
-
- This method involves manipulations of the interrupt vectors,
- mainly for proper activation of the algorithm. Such action, as
- exampled, may be used to decrypt a code (see also 2.1), using data
- stored ON the vectors. Ofcourse, during normal operation of the
- program, vectors 01h and 03h are not used, so unless you are trying
- to debug such a program, it works fine.
-
- Example:
-
- CS:0100 31C0 XOR AX,AX
- CS:0102 8ED0 MOV SS,AX
- CS:0104 BC0600 MOV SP,0006
- CS:0107 8B0E0211 MOV CX,[1102]
- CS:010B 50 PUSH AX
- CS:010C 21C8 AND AX,CX
- CS:010E 01C5 ADD BP,AX
- CS:0110 58 POP AX
- CS:0111 E2F8 LOOP 010B
-
- 1.1.4. Interrupt replacement
-
- This is a really nasty trick, and it should be used ONLY if you
- are ABSOLUTELY sure that your programs needs no more debugging. What
- it does is simply copy the vectors of some interrupts you will be
- using, say 16h and 21h, onto the vectors of interrupt 01h and 03h,
- that do not occure during normal operation of the program. If the
- user wants to debug the program, he would have to search for every
- occurance of INT 01, and replace it with the appropriate INT
- instruction.
-
- Example:
-
- CS:0100 FA CLI
- CS:0101 31C0 XOR AX,AX
- CS:0103 8EC0 MOV ES,AX
- CS:0105 26A18400 MOV AX,ES:[0084]
- CS:0109 26A30400 MOV ES:[0004],AX
- CS:010D 26A18600 MOV AX,ES:[0086]
- CS:0111 26A30600 MOV ES:[0006],AX
- CS:0115 B44C MOV AH,4C
- CS:0117 CD01 INT 01
-
- 1.2. Time watch:
-
- This may be a less common method, but it is usefull against debuggers
- that disable all interrupts except for the time that the program is
- executed, such as Borland's Turbo Debugger. This method simply retains
- the value of the clock counter, updated by interrupt 08h, and waits in an
- infinite loop until the value changes. Another example is when you mask
- the timer interrupt by ORing the value INed from port 21h with 01h and
- then OUTing it back, thus disabling the IRQ0 - Timer interrupt. Note that
- this method is usefull only against RUN actions, not TRACE/PROCEED ones.
-
- Example:
-
- CS:0100 2BC0 SUB AX,AX
- CS:0102 FB STI
- CS:0103 8ED8 MOV DS,AX
- CS:0105 8A266C04 MOV AH,[046C]
- CS:0109 A06C04 MOV AL,[046C]
- CS:010C 3AC4 CMP AL,AH
- CS:010E 74F9 JZ 0109
-
- 1.3. Fool the debugger:
-
- This is a very nice technique, that works especially and only on those
- who use Turbo Debugger or its kind. What you do is init a jump to a
- middle of an instruction, whereas the real address actually contains
- another opcode. If you work with a normal step debugger such as Debug or
- SymDeb, it won't work since the debugger jumps to the exact address of
- the jump, and not to the beginning of an instruction at the closest
- address, like Turbo Debugger.
-
- Example:
-
- CS:0100 E421 IN AL,21
- CS:0102 B0FF MOV AL,FF
- CS:0104 EB02 JMP 0108
- CS:0106 C606E62100 MOV Byte Ptr [21E6],00
- CS:010B CD20 INT 20
-
- Watch this:
-
- CS:0108 E621 OUT 21,AL
-
- 1.4. Cause debugger to stop execution:
-
- This is a technique that causes a debugger to stop the execution of a
- certain program. What you need to do is to put some INT 3 instructions
- over the code, at random places, and any debugger trying to run will stop
- there. Since this techniqu causes the CPU to stop executing the program,
- and therefore clear the Prefetch Instruction Queue, it is adviseable to
- use this techinque in conjunction with the PIQ trick, 2.2.2. Note that
- the example shows how to use these two tricks together.
-
- Example:
-
- CS:0100 B97502 MOV CX,0275
- CS:0103 BE9001 MOV SI,0190
- CS:0106 89F7 MOV DI,SI
- CS:0108 AC LODSB
- CS:0109 C70610013473 MOV Word Ptr [0110],7334
- CS:010F CC INT 3
- CS:0110 2406 AND AL,06
- CS:0112 AA STOSB
- CS:0113 C70610012406 MOV Word Ptr [0110],0624
- CS:0119 E2ED LOOP 0108
-
- 1.5. Halt TD386 V8086 mode:
-
- This is a nice way to fool Turbo Debugger's V8086 module (TD386). It is
- baed on the fact that TD386 does not use INT 00h to detect division by
- zero (or register overrun after division, which is treated by the
- processor in the same way as in case of division by zero). When TD386
- detects a division fault it aborts, reporting about the faulty
- division. In real mode (even under a regular debugger), a faulty DIV
- instruction will cause INT 00h to be called. Therefore, pointing INT 00h
- to the next instruction, will recover from the faulty DIV.
-
- Note: It is very important to restore INT 00h's vector. Otherwise, the
- next call to INT 00h will cause the machine to hang.
-
- Example:
-
- CS:0100 31C0 XOR AX,AX
- CS:0102 8ED8 MOV DS,AX
- CS:0104 C70600001201 MOV WORD PTR [0000],0112
- CS:010A 8C0E0200 MOV [0002],CS
- CS:010E B400 MOV AH,00
- CS:0110 F6F4 DIV AH
- CS:0112 B8004C MOV AX,4C00
- CS:0115 CD21 INT 21
-
- 1.6. Halt any V8086 process:
-
- Another way of messing TD386 is fooling it into an exception.
- Unfortunately, this exception will also be generated under any other
- program, running at V8086 mode. The exception is exception #13, and its
- issued interrupt is INT 0Dh - 13d. The idea is very similar to the
- divide by zero trick: Causing an exception, when the exception interrupt
- points to somewhere in the program's code. It will always work when the
- machine is running in real mode, but never under the V8086 mode.
-
- Note: It is very important to restore the original interrupt vectors.
- Otherwise, the next exception will hang the machine.
-
- Example:
-
- CS:0100 31C0 XOR AX,AX
- CS:0102 8ED8 MOV DS,AX
- CS:0104 C70634001301 MOV WORD PTR [0034],0113
- CS:010A 8C0E3600 MOV [0036],CS
- CS:010E 833EFFFF00 CMP WORD PTR [FFFF],+00
- CS:0113 B8004C MOV AX,4C00
- CS:0116 CD21 INT 21
-
- 2. Self-modifying code:
- -----------------------
-
- 2.1. Encryptive/decryptive algorithm:
-
- The first category is simply a code, that has been encrypted, and has
- been added with a decryption routine. The trick here is that when a
- debugger sets up a breakpoint, it simply places the opcode CCh (INT 03h)
- in the desired address, and once that interrupt is executed, the debugger
- regains control of things. If you try to set a breakpoint AFTER the
- decryption algorithm, what is usually needed, you will end up putting an
- opcode CCh in a place where decryption action is taken, therefore losing
- your original CCh in favour of whatever the decryption algorithm makes.
- The following example was extracted from the Haifa virus. If you try to
- set a breakpoint at address CS:0110, you will never reach that address,
- since there is no way to know what will result from the change. Note that
- if you want to make the tracing even harder, you should start the
- decryption of the code from its END, so it takes the whole operation
- until the opcode following the decryption routine is decrypted.
-
- Example:
-
- CS:0100 BB7109 MOV BX,0971
- CS:0103 BE1001 MOV DI,0110
- CS:0106 91 XCHG AX,CX
- CS:0107 91 XCHG AX,CX
- CS:0108 2E803597 XOR Byte Ptr CS:[DI],97
- CS:010C 47 INC DI
- CS:010D 4B DEC BX
- CS:010E 75F6 JNZ 0106
- CS:0110 07 POP ES
- CS:0111 07 POP ES
-
- 2.2. Self-modifying code:
-
- 2.2.1. Simple self-modification:
-
- This method implements the same principle as the encryption
- method: Change the opcode before using it. In the following example,
- we change the insruction following the call, and therefore, if you
- try to trace the entire call ('P'/Debug or F8/Turbo Debugger), you
- will not succeed, since the debugger will put its CCh on offset 104h,
- but when the routine runs, it overwrites location 104h.
-
- Example:
-
- CS:0100 E80400 CALL 0107
- CS:0103 CD20 INT 20
- CS:0105 CD21 INT 21
- CS:0107 C7060301B44C MOV Word Ptr [0103],4CB4
- CS:010D C3 RET
-
- Watch this:
-
- CS:0103 B44C MOV AH,4C
-
- 2.2.2. Prefetch Instruction Queue (PIQ) manipulation:
-
- This method is a bit similar to (1.3), but it fools ANY debugger,
- or any other process that executes one operation at a time. The PIQ
- is an area within the CPU, that pre-fethces, ie. takes in advance,
- instructions from memory, so when they need to be executed, it
- would take less time to get them, since they are already in the CPU.
- The PIQ length ranges from 6 or 4 in old computers, up to as high as
- 25 in new ones. What the trick does is change the FOLLOWING opcode
- to something meaningless. If you are debugging, then the change will
- take place BEFORE the instructions is executed or fetched. If you
- run the program NORMALLY, by the time you change the opcode, it will
- have already been fetched.
-
- Example:
-
- CS:0100 B97502 MOV CX,0275
- CS:0103 BE9001 MOV SI,0190
- CS:0106 89F7 MOV DI,SI
- CS:0108 AC LODSB
- CS:0109 C7060F012406 MOV Word Ptr [010F],0624
- CS:010F 3473 XOR AL,73
- CS:0111 AA STOSB
- CS:0112 C7060F012406 MOV Word Ptr [010F],0624
- CS:0118 E2EE LOOP 0108
-
- Watch this:
-
- CS:010F 2406 AND AL,06
-
- ===============================================================================
-
- Thanks to Yogo and Ford Prefect for helping me assemble this list.
-
- Any new ideas and updates should be sent to: Inbar Raz, 2:401/100.1 or
- 2:403/123.42.
-
- Inbar Raz
-
-